/*
 * Copyright (C) 2014 Miquel Sas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package traderlib.core.data.db;

import traderlib.core.data.entity.Field;

/**
 * A column of a table or view.
 *
 * @author Miquel Sas
 */
public class Column extends Field {

	/**
	 * A supported database function if the column is virtual or calculated.
	 */
	private String function = null;
	/**
	 * The parent table.
	 */
	private Table parentTable = null;
	/**
	 * Optional parent view
	 */
	private View parentView = null;

	/**
	 * Default constructor.
	 */
	public Column() {
		super();
	}

	/**
	 * Copy contructor.
	 *
	 * @param column The column to copy
	 */
	public Column(Column column) {
		super(column);
		this.function = column.function;
		this.parentTable = column.parentTable;
		this.parentView = column.parentView;
	}

	/**
	 * Gets the function or formula.
	 *
	 * @return The function.
	 */
	public String getFunction() {
		return function;
	}

	/**
	 * Sets the function or formula.
	 *
	 * @param function The function.
	 */
	public void setFunction(String function) {
		this.function = null;
		if (function != null && function.trim().length() > 0) {
			this.function = function.trim();
		}
	}

	/**
	 * Check if this column is virtual. A column is virtual is it has a function but not a name.
	 *
	 * @return A <code>boolean</code>.
	 */
	public boolean isVirtual() {
		return (getFunction() != null);
	}

	/**
	 * Check if this column has to create constraints.
	 *
	 * @return A boolean.
	 */
	public boolean isCreateConstraints() {
		if (!isPersistent()) {
			return false;
		}
		if (getParentTable() == null) {
			return false;
		}
		if (!getParentTable().isPersistentConstraints()) {
			return false;
		}
		if (getMinimumValue() != null) {
			return true;
		}
		if (getMaximumValue() != null) {
			return true;
		}
		if (getPossibleValues() != null) {
			if (!getPossibleValues().isEmpty()) {
				if (!isBoolean()) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Return this columnn parent table.
	 *
	 * @return The parent table.
	 */
	public Table getParentTable() {
		return parentTable;
	}

	/**
	 * Set this column parent table.
	 *
	 * @param parentTable The parent table.
	 */
	public void setParentTable(Table parentTable) {
		this.parentTable = parentTable;
	}

	/**
	 * Return this column parent view.
	 *
	 * @return The parent view
	 */
	public View getParentView() {
		return parentView;
	}

	/**
	 * Set this column parent view if any.
	 *
	 * @param parentView The parent view
	 */
	public void setParentView(View parentView) {
		this.parentView = parentView;
	}

	/**
	 * Returns the name of the column in the database, qualified with the parent table or view alias if it exists.
	 *
	 * @return The name.
	 */
	public String getNameParent() {
		String name = getName();
		String parentAlias = (getParentTable() != null ? getParentTable().getAlias() : null);
		if (parentAlias != null) {
			return parentAlias + "." + name;
		}
		return name;
	}

	/**
	 * Returns the name to use in a relation of a select statement.
	 *
	 * @return The name.
	 */
	public String getNameRelate() {
		return getNameParent();
	}

	/**
	 * Returns the name to use in an <code>UPDATE</code> statement.
	 *
	 * @return The name.
	 */
	public String getNameUpdate() {
		String name = getName();
		String parentName = (parentTable != null ? parentTable.getName() : null);
		if (parentName != null) {
			return parentName + "." + name;
		}
		return name;
	}

	/**
	 * Returns the name to use in an <code>DELETE</code> statement.
	 *
	 * @return The name.
	 */
	public String getNameDelete() {
		return getNameUpdate();
	}

	/**
	 * Returns the name to use in a <code>WHERE</code> clause.
	 *
	 * @return The name.
	 */
	public String getNameWhere() {
		if (isVirtual()) {
			return "(" + getFunction() + ")";
		}
		return getNameParent();
	}

	/**
	 * Returns the name to use in the column list of a <code>SELECT</code> query.
	 *
	 * @return The name.
	 */
	public String getNameSelect() {
		StringBuilder name = new StringBuilder();
		if (isVirtual()) {
			name.append("(");
			name.append(getFunction());
			name.append(")");
		} else {
			name.append(getNameParent());
		}
		if (getAlias() != null) {
			name.append(" AS ");
			name.append(getAlias());
		}
		return name.toString();
	}

	/**
	 * Gets the name to use in a <code>CREATE TABLE</code> or <code>ALTER TABLE</code> statement.
	 *
	 * @return The name.
	 */
	public String getNameCreate() {
		return getName();
	}

	/**
	 * Returns the name to use in a <code>GROUP BY</code> clause of a <code>SELECT</code> query.
	 *
	 * @return The name.
	 */
	public String getNameGroupBy() {
		StringBuilder name = new StringBuilder();
		if (isVirtual()) {
			name.append("(");
			name.append(getFunction());
			name.append(")");
		} else {
			name.append(getNameParent());
		}
		return name.toString();
	}

	/**
	 * Returns the name to use in an <code>ORDER BY</code> clause of a select query.
	 *
	 * @return The name.
	 */
	public String getNameOrderBy() {
		StringBuilder name = new StringBuilder();
		if (isVirtual()) {
			name.append("(");
			name.append(getFunction());
			name.append(")");
		} else {
			name.append(getNameParent());
		}
		return name.toString();
	}
}
